import { JSEncrypt } from 'jsencrypt'
import { rsaPrivateKey, rsaPublicKey } from './rsa_key'
import jsmd5 from 'js-md5'
import aesjs from 'aes-js'
import CryptoJS from 'crypto-js'
// DH密钥交换插件
const crypto = require('crypto-browserify')

const Base64 = require('js-base64').Base64

const publicKey = rsaPublicKey
const privateKey = rsaPrivateKey

aesjs.ModeOfOperation.Ecb = aesjs.ModeOfOperation.ecb

// md5生成摘要
export const md5 = (content) => {
  return jsmd5(content)
}

// md5转arraybuffer
export const md5ArrayBuffer = (ab) => {
  return jsmd5.arrayBuffer(ab)
}

// Base64转码
export const Base64Encode = (value) => {
  return Base64.encode(value)
}

// Base64解码
export const Base64Decode = (value) => {
  return Base64.decode(value)
}

// RSA加密
/**
 * @param {文本值} value
*/
export const encryptPublic = (value) => {
  const secret = new JSEncrypt({
    default_key_size: 512
  })

  secret.setPublicKey(publicKey)
  const encrypted = secret.encrypt(value)
  return encrypted
}

// RSA解密
/**
 * @param {文本值} value
 */
export const decryptPrivate = (value) => {
  const secret = new JSEncrypt({
    default_key_size: 512
  })
  secret.setPrivateKey(privateKey)

  const decrypted = secret.decrypt(value)
  return decrypted
}

// 动态生成AES密钥
export const createAesKey = () => {
  const expert = 16
  let str = Math.random().toString(36).substr(2)
  while (str.length < expert) {
    str += Math.random().toString(36).substr(2)
  }
  str = str.substr(0, 16)
  return str
}

// aes-js加密
export const aesEncrypt = (content, key) => {
  let keyBytes
  if (typeof key === 'string') {
    keyBytes = aesjs.utils.utf8.toBytes(key)
  } else {
    keyBytes = key
  }
  const aesEcb = new aesjs.ModeOfOperation.Ecb(keyBytes)
  if (typeof content === 'string') {
    content = aesjs.utils.utf8.toBytes(content)
  }
  const times = (Math.floor(content.length / 16) + 1) * 16 - content.length
  const barray = new Uint8Array((Math.floor(content.length / 16) + 1) * 16)
  for (let i = 0; i < barray.length; i++) {
    if (content[i] || content[i] === 0) {
      barray[i] = content[i]
    } else {
      barray[i] = times
    }
  }
  const encryptedBytes = aesEcb.encrypt(barray)
  return encryptedBytes
}

// aes-js解密
export const aesDecrypt = (content, key, ifSocket) => {
  const uint = new Uint8Array(content)
  let keyBytes
  if (typeof key === 'string') {
    keyBytes = aesjs.utils.utf8.toBytes(key)
  } else {
    keyBytes = key
  }
  const aesEcb = new aesjs.ModeOfOperation.Ecb(keyBytes)
  const decryptedBytes = aesEcb.decrypt(uint)
  const times = decryptedBytes[decryptedBytes.length - 1]
  const barray = new Uint8Array(decryptedBytes.length - times)
  for (let i = 0; i < barray.length; i++) {
    barray[i] = decryptedBytes[i]
  }
  if (ifSocket) {
    return barray
  }
  const decryptedText = aesjs.utils.utf8.fromBytes(barray)
  return decryptedText
}

// crypto-js加密
export const cryptoEncrypt = (content, key) => {
  const srcs = CryptoJS.enc.Utf8.parse(content)
  const encrypted = CryptoJS.AES.encrypt(srcs, key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 })
  return encrypted
}

// crypto-js解密
export const cryptoDecrypt = (content, key) => {
  const decrypt = CryptoJS.AES.decrypt(content, key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 })
  const decryptedStr = decrypt.toString(CryptoJS.enc.Utf8)
  return decryptedStr.toString()
}

// DH密钥交换
export const DH = crypto.getDiffieHellman('modp2')
// 生成密钥对象
DH.generateKeys()

// uint8转string
export const uint8ToStr = (uint8array) => {
  // let dataString = ''
  // for (let i = 0; i < uint8array.length; i++) {
  //   dataString += String.fromCharCode(uint8array[i])
  // }
  // return dataString
  let str = ''
  const arr = uint8array
  for (let i = 0; i < arr.length; i++) {
    const one = arr[i].toString(2)
    const v = one.match(/^1+?(?=0)/)
    if (v && one.length === 8) {
      const bytesLength = v[0].length
      let store = arr[i].toString(2).slice(7 - bytesLength)
      for (let st = 1; st < bytesLength; st++) {
        store += arr[st + i].toString(2).slice(2)
      }
      str += String.fromCharCode(parseInt(store, 2))
      i += bytesLength - 1
    } else {
      str += String.fromCharCode(arr[i])
    }
  }
  return str
}
